﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Collections;

/// <summary>
/// Represents meta data in a PO file entry
/// PO specification at http://www.gnu.org/software/autoconf/manual/gettext/PO-Files.html
/// </summary>
public class POMetaData
{
    private string context = null;
    private string untranslatedPlural = null;
    private Dictionary<int, Dictionary<string, string>> translatedPlurals = null;

    /// <summary>
    /// Gets or sets the programmer's comments (extracted from the source code)
    /// </summary>
    /// <value>The programmers comments.</value>
    public List<string> ExtractedComments { get; set; }

    /// <summary>
    /// Gets or sets the translator's comments
    /// </summary>
    /// <value>The translator's comments.</value>
    public Dictionary<string, string> TranslatorsComments { get; set; }

    /// <summary>
    /// Gets or sets the source code reference to which this entry applies.
    /// </summary>
    /// <value>The reference.</value>
    public List<string> References { get; set; }

    /// <summary>
    /// Gets or sets the flags.
    /// </summary>
    /// <value>The flags.</value>
    public List<string> Flags { get; set; }

    /// <summary>
    /// Gets or sets the untranslated string.
    /// </summary>
    /// <value>The untranslated string.</value>
    public string UntranslatedString { get; set; }

    /// <summary>
    /// Gets or sets the translated string.
    /// </summary>
    /// <value>The translated string.</value>
    public string TranslatedString { get; set; }
    
    /// <summary>
    /// Gets or sets the context of the untranslated string, which is needed if more than one entry has the same untranslated string.
    /// </summary>
    /// <value>The context.</value>
    public string Context {
        get { return context; }
        set { context = value; }
    }

    /// <summary>
    /// Gets or sets the untranslated plural (null if none exists).
    /// </summary>
    /// <value>The untranslated plural.</value>
    public string UntranslatedPlural {
        get { return untranslatedPlural; }
        set { untranslatedPlural = value; }
    }

    /// <summary>
    /// Gets or sets the translated plurals for this entry.
    /// <Number, <languageCode, Translation>>
    /// </summary>
    /// <value>The translated plurals.</value>
    public Dictionary<int, Dictionary<string,string>> TranslatedPlurals {
        get { return translatedPlurals; }
        set { translatedPlurals = value; }
    }

	public POMetaData() {
        ExtractedComments = new List<string>();
        TranslatorsComments = new Dictionary<string, string>();
        References = new List<string>();
        Flags = new List<string>();
        UntranslatedString = string.Empty;
        TranslatedString = string.Empty;
	}

    /// <summary>
    /// Gets a textual representation of this meta data including source comments, references and flags which can be stored in an element comments field
    /// Does NOT include translators' comments
    /// </summary>
    /// <returns></returns>
    public string ToCommentsField() {
        StringBuilder buffer = new StringBuilder();
        if(ExtractedComments.Count > 0) {
            foreach(string comment in ExtractedComments) {
                buffer.Append("#. ").Append(comment).Append("\n");
            }
        }
        if(References.Count > 0) {
            foreach(string reference in References) {
                buffer.Append("#: ").Append(reference).Append("\n");
            }
        }
        if(Flags.Count > 0) {
            foreach(string flag in Flags) {
                buffer.Append("#, ").Append(flag).Append("\n");
            }
        }
        if(context != null) {
            buffer.Append("msgctxt \"").Append(context).Append("\"");
        }
        return buffer.ToString();
    }


    /// <summary>
    /// Parses source comments, references, flags and the msgctxt from PO entry meta data.
    /// Does NOT parse translator's comments or translation data.
    /// </summary>
    /// <param name="rawMetaData">The raw meta data.</param>
    /// <returns>An object containing the meta data</returns>
    public static POMetaData Parse(string rawMetaData) {
        POMetaData data = new POMetaData();
        if(rawMetaData != null && rawMetaData.Length > 0) {
            string[] lines = rawMetaData.Split('\n');
            foreach(string line in lines) {
                if(line.Length < 4) {
                    continue;
                }
                switch(line.Substring(0, 2)) {
                    case "#.":
                        data.ExtractedComments.Add(line.Substring(2).Trim());
                        break;
                    case "#:":
                        data.References.Add(line.Substring(2).Trim());
                        break;
                    case "#,":
                        data.Flags.Add(line.Substring(2).Trim());
                        break;
                    default:
                        if(line.StartsWith("msgctxt")) {
                            if(line == "msgctxt \"\"") {
                                data.Context = string.Empty;
                            } else if(line.Length >= 11) {
                                data.Context = line.Substring(9, line.Length - 10);
                            }
                        }
                        break;
                }
            }
        }
        return data;
    }

    public POMetaData Clone() {
        POMetaData clone = new POMetaData();
        clone.Context = this.context;
        clone.ExtractedComments = this.ExtractedComments;
        clone.TranslatorsComments = this.TranslatorsComments;
        clone.References.AddRange(this.References);
        clone.Flags.AddRange(this.Flags);
        clone.UntranslatedString = this.UntranslatedString;
        clone.TranslatedString = this.TranslatedString;
        clone.UntranslatedPlural = this.UntranslatedPlural;
        clone.TranslatedPlurals = this.TranslatedPlurals;
        return clone;
    }
}
